package org.xtremeobjects.domain.states.scxml;

import java.util.List;

import org.apache.commons.scxml.model.Executable;
import org.apache.commons.scxml.model.OnEntry;
import org.apache.commons.scxml.model.OnExit;
import org.apache.commons.scxml.model.SCXML;
import org.xtremeobjects.domain.states.Action;
import org.xtremeobjects.domain.states.State;
import org.xtremeobjects.domain.states.StateMachine;
import org.xtremeobjects.domain.states.Transition;

public class StateMachineToSCXML {
	
	static public SCXML createFrom(StateMachine sm) {
		SCXML scxml = new SCXML();
		scxml.setXmlns("http://www.w3.org/2005/07/scxml");
		scxml.setVersion("1.0");
		for (State state : sm.getStates()) {
			addState(scxml, state);
		}
		scxml.setInitialstate(sm.start().getId());
		return scxml;
	}

	private static void addState(SCXML scxml, State state) {
		org.apache.commons.scxml.model.Final st = new org.apache.commons.scxml.model.Final();
		st.setId(state.getId());
		scxml.addState(st);
		
		for (Transition transition : state.getTransitions()) {
			org.apache.commons.scxml.model.Transition tr = new org.apache.commons.scxml.model.Transition();
			tr.setParent(st);
			tr.setNext(transition.getTo().getId());
			if(transition.getEvent()!=null)
				tr.setEvent(transition.getEvent().getId());
			if(transition.getGuard()!=null && !transition.getGuard().getExpression().isEmpty())
				tr.setCond(transition.getGuard().getExpression());
			st.addTransition(tr);
		}
		
		for (State childState : state.getStates()) {
			addState(scxml, childState);
		}

		addActionsForEntry(state.getActionsForEvent(State.ENTRY), st);
		addActionsForExit(state.getActionsForEvent(State.EXIT), st);
	}

	private static void addActionsForEntry(List<Action> actions, org.apache.commons.scxml.model.Final st) {
		if(actions!=null) {
			OnEntry onEntry = st.getOnEntry();
			if(onEntry==null) {
				onEntry = new OnEntry();
				st.setOnEntry( onEntry ); 
			}
			addActions(actions, onEntry);
		}
	}
	
	private static void addActionsForExit(List<Action> actions, org.apache.commons.scxml.model.Final st) {
		if(actions!=null) {
			OnExit onExit = st.getOnExit();
			if(onExit==null) {
				onExit = new OnExit();
				st.setOnExit( onExit ); 
			}
			addActions(actions, onExit);
		}
	}
	

	private static void addActions(List<Action> actions, Executable executable) {
		for (Action action : actions) {
			org.apache.commons.scxml.model.Var newAction = new org.apache.commons.scxml.model.Var();
			newAction.setExpr(action.getText());
			executable.addAction(newAction);
		}
	}
}
